/*
 * Copyright (c) 2010 Mathias Garbe <code@mathias-garbe.de>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "SettingsWindow.hpp"

SettingsWindow::SettingsWindow(QWidget *parent, Qt::WFlags flags)
: QDialog(parent, flags)
{
    this->mainWindow = reinterpret_cast<MainWindow*>(parent);
    //this->mainWindow->refreshGames();

    QWidget::setWindowModality(Qt::WindowModal);
    ui.setupUi(this);

    this->addPathWindow = new AddPathWindow();

    QRect screen = QApplication::desktop()->screenGeometry();
    this->move(screen.width()/2 - this->width()/2, screen.height()/2 - this->height()/2);

    connect(this->ui.pushApply, SIGNAL(clicked()), this, SLOT(applySettings()));
    connect(this->ui.pushCancel, SIGNAL(clicked()), this, SLOT(closeSettings()));

    connect(this->ui.pushBrowseTD, SIGNAL(clicked()), this, SLOT(setTDPath()));
    connect(this->ui.pushBrowseRA, SIGNAL(clicked()), this, SLOT(setRAPath()));
    connect(this->ui.pushBrowseTS, SIGNAL(clicked()), this, SLOT(setTSPath()));
    connect(this->ui.pushBrowseRA2, SIGNAL(clicked()), this, SLOT(setRA2Path()));
    connect(this->ui.pushBrowseRA2YR, SIGNAL(clicked()), this, SLOT(setRA2YRPath()));

    connect(this->ui.checkAdvancedSettings, SIGNAL(stateChanged(int)), this, SLOT(toggleAdvancedSettings(int)));

    connect(this->ui.tabCustomAdvanced, SIGNAL(currentChanged(int)), this, SLOT(customPathAdvTabChanged(int)));

    connect(this->ui.pushCustomAdvAdd, SIGNAL(clicked()), this, SLOT(addCustomPath()));
    connect(this->ui.pushCustomAdvEdit, SIGNAL(clicked()), this, SLOT(editCustomPath()));
    connect(this->ui.pushCustomAdvDelete, SIGNAL(clicked()), this, SLOT(delCustomPath()));

    this->ui.treeCustomPaths->setRootIsDecorated(false);
    this->ui.treeCustomPaths->setAlternatingRowColors(true);
    this->customAdvPathModel = new QStandardItemModel(0, 3, parent);
    this->customAdvPathModel->setHeaderData(0, Qt::Horizontal, QObject::tr("Name"));
    this->customAdvPathModel->setHeaderData(1, Qt::Horizontal, QObject::tr("Exe path"));
    this->customAdvPathModel->setHeaderData(2, Qt::Horizontal, QObject::tr("Arguments"));
    this->ui.treeCustomPaths->setModel(this->customAdvPathModel);

    this->ui.treeCustomPaths->setColumnWidth(0, 105);
    this->ui.treeCustomPaths->setColumnWidth(1, 300);
    this->ui.treeCustomPaths->setColumnWidth(2, 80);

    // ComboBox Item data for ddraw tab
    this->ui.comboDDrawColor->setItemData(0, "0");
    this->ui.comboDDrawColor->setItemData(1, "32");
    this->ui.comboDDrawColor->setItemData(2, "24");
    this->ui.comboDDrawColor->setItemData(3, "16");

    this->ui.comboDDrawFilter->setItemData(0, "linear");
    this->ui.comboDDrawFilter->setItemData(1, "nearest");

    this->ui.comboDDrawFps->setItemData(0, "-1");
    this->ui.comboDDrawFps->setItemData(1, "0");
    this->ui.comboDDrawFps->setItemData(2, "1");
}

SettingsWindow::~SettingsWindow()
{
    delete this->addPathWindow;
}

void SettingsWindow::show()
{
    QWidget::show();
    this->closed = false;

    for(int i=0; i<5; i++)
    {
        this->customAdvPaths[i].clear();
    }

    this->loadSettings();
    this->rebuildTabs();
    this->ui.tabWidget->setCurrentIndex(0);

    // Setup advanced path stuff
    rebuildPathTree();

    QSettings settings;

    bool firstStart = settings.value("General/FirstStart", true).toBool();
    if(firstStart)
    {
        QMessageBox msgBox;
        msgBox.setWindowTitle("First start");
        msgBox.setText("It seems that this is the first start of CnCnet (or you updated to a new release). Please check your settings.");
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.setDefaultButton(QMessageBox::Ok);
        msgBox.setIcon(QMessageBox::Information);
        msgBox.exec();
    }
}

void SettingsWindow::closeEvent(QCloseEvent *event)
{
    QMessageBox msgBox;
    msgBox.setWindowTitle("CnCnet settings");

    QSettings settings;
    bool firstStart = settings.value("General/FirstStart", true).toBool();
    if(firstStart)
    {
        msgBox.setText("Since this is the first start of the client, you have to apply your settings.");
        msgBox.setInformativeText("If you do not, the client will exit. Do you want to close this window anyway?");
        msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
        msgBox.setDefaultButton(QMessageBox::No);
        msgBox.setIcon(QMessageBox::Warning);
        int ret = msgBox.exec();

        if(ret == QMessageBox::No)
        {
            event->ignore();
        }
        else
        {
            exit(0);
        }
    }
    else
    {
        if(closed)
        {
            this->closed = true;
            this->mainWindow->refreshGames();
            this->mainWindow->updateOnlineStatus();
            this->mainWindow->checkIrc();
            this->mainWindow->rebuildTabs();
            event->accept();
            return;
        }
        msgBox.setText("Are you sure want to close?");
        msgBox.setInformativeText("All unsaved changes will be lost!");
        msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
        msgBox.setDefaultButton(QMessageBox::No);
        msgBox.setIcon(QMessageBox::Warning);
        int ret = msgBox.exec();

        if(ret == QMessageBox::No)
        {
            event->ignore();
        }
        else
        {
            this->closed = true;
            this->mainWindow->refreshGames();
            this->mainWindow->updateOnlineStatus();
            event->accept();
        }
    }
}


void SettingsWindow::rebuildTabs()
{
    bool useAdvancedSettings = (this->ui.checkAdvancedSettings->checkState() == Qt::Checked ? true : false);

    // Remove all tabs
    int count = this->ui.tabWidget->count();

    for(int i=0; i<count; i++)
    {
        this->ui.tabWidget->removeTab(0);
    }

    count = 0;

    this->ui.tabWidget->insertTab(count++, this->ui.tabGeneral, "General");
    this->ui.tabWidget->insertTab(count++, this->ui.tabIrc, "IRC");
    this->ui.tabWidget->insertTab(count++, this->ui.tabDDraw, "DirectDraw");

    if(!useAdvancedSettings)
    {
        this->ui.tabWidget->insertTab(count++, this->ui.tabGamesSimple, "Custom Paths");
    }
    else
    {
        this->ui.tabWidget->insertTab(count++, this->ui.tabNetwork, "Network");
        this->ui.tabWidget->insertTab(count++, this->ui.tabGamesAdvanced, "Custom Paths"); // (Advanced)");
    }
}

void SettingsWindow::rebuildPathTree()
{
    int max = this->customAdvPathModel->rowCount();
    for(int i=0; i<max; i++)
    {
        this->customAdvPathModel->removeRows(0, 1);
    }

    int game = this->ui.tabCustomAdvanced->currentIndex();

    for (std::vector<AdvancedGameInfo>::iterator it = this->customAdvPaths[game].begin(); it!=this->customAdvPaths[game].end(); ++it) 
    {
        AdvancedGameInfo tmpGameInfo = (*it);

        int s = this->customAdvPathModel->rowCount();
        this->customAdvPathModel->insertRow(s);
        this->customAdvPathModel->setData(customAdvPathModel->index(s, 0), tmpGameInfo.getDescription().c_str());
        this->customAdvPathModel->setData(customAdvPathModel->index(s, 1), tmpGameInfo.getExe().c_str());
        this->customAdvPathModel->setData(customAdvPathModel->index(s, 2), tmpGameInfo.getArgs().c_str());
    }
}

void SettingsWindow::loadSettings()
{
    QSettings settings;
    int settingsVersion = settings.value("General/Version", "0").toInt(); 


    if(settingsVersion < _SETTINGS_VERSION)
    {
        // Check if settings point to old server
        if(settings.value("Network/Server", "lobby.cncnet.cnc-comm.com").toString() == "hifi.iki.fi")
        {
            settings.setValue("Network/Server", "lobby.cncnet.cnc-comm.com");
            settings.sync();
        }
    }

    this->ui.lineNickname->setText(settings.value("General/GameHandle", "").toString());
    this->ui.lineServer->setText(settings.value("Network/Server", "lobby.cncnet.cnc-comm.com").toString());
    this->ui.lineServerPort->setText(settings.value("Network/ServerPort", "8054").toString());
    this->ui.lineClientPort->setText(settings.value("Network/ClientPort", "8054").toString());

    this->ui.lineTD->setText(settings.value("CustomPath/TD", "").toString());
    this->ui.lineRA->setText(settings.value("CustomPath/RA", "").toString());
    this->ui.lineTS->setText(settings.value("CustomPath/TS", "").toString());
    this->ui.lineRA2->setText(settings.value("CustomPath/RA2", "").toString());
    this->ui.lineRA2YR->setText(settings.value("CustomPath/RA2YR", "").toString());

    this->ui.checkUpdateStartup->setCheckState((settings.value("General/UpdateOnStartup", true).toBool() ? Qt::Checked : Qt::Unchecked));
    this->ui.checkConfirmGameLaunch->setCheckState((settings.value("General/ConfirmGameLaunch", true).toBool() ? Qt::Checked : Qt::Unchecked));
    this->ui.checkMinimizeTray->setCheckState((settings.value("General/MinimizeToTray", true).toBool() ? Qt::Checked : Qt::Unchecked));
    this->ui.checkPortForce->setCheckState((settings.value("Network/ClientPortForce", false).toBool() ? Qt::Checked : Qt::Unchecked));

    this->ui.checkAdvancedSettings->setCheckState((settings.value("General/AdvancedSettings", false).toBool() ? Qt::Checked : Qt::Unchecked));

    this->ui.checkIrcEnabled->setCheckState((settings.value("IRC/Enabled", true).toBool() ? Qt::Checked : Qt::Unchecked));
    this->ui.checkIrcTimestamp->setCheckState((settings.value("IRC/Timestamp", false).toBool() ? Qt::Checked : Qt::Unchecked));
    this->ui.lineIrcNickname->setText(settings.value("IRC/Nickname", "").toString());

    // populate advanced path vectors
    for(int game=0; game<5; game++)
    {
        this->customAdvPaths[game] = AdvancedGameInfo::loadGameInfos(game);
    }


    this->ui.checkDDrawEnabled->setCheckState((settings.value("CNC-DDraw/Enabled", false).toBool() ? Qt::Checked : Qt::Unchecked));
    this->ui.checkDDrawWindowed->setCheckState((settings.value("CNC-DDraw/Windowed", true).toBool() ? Qt::Checked : Qt::Unchecked));
    this->ui.checkDDrawAdjustMouse ->setCheckState((settings.value("CNC-DDraw/AdjustMouse", false).toBool() ? Qt::Checked : Qt::Unchecked));

    this->ui.lineDDrawWidth->setText(settings.value("CNC-DDraw/Width", "").toString());
    this->ui.lineDDrawHeight->setText(settings.value("CNC-DDraw/Height", "").toString());

    if(settings.value("CNC-DDraw/Filter", "linear").toString() == "linear")
    {
        this->ui.comboDDrawFilter->setCurrentIndex(0);
    }
    else
    {
        this->ui.comboDDrawFilter->setCurrentIndex(1);
    }

    int color = settings.value("CNC-DDraw/Color", "0").toInt();
    if(color == 0)
    {
        this->ui.comboDDrawColor->setCurrentIndex(0);
    }
    else if(color == 32)
    {
        this->ui.comboDDrawColor->setCurrentIndex(1);
    }
    else if(color == 24)
    {
        this->ui.comboDDrawColor->setCurrentIndex(2);
    }
    else
    {
        this->ui.comboDDrawColor->setCurrentIndex(3);
    }

    int fps = settings.value("CNC-DDraw/Fps", "-1").toInt();
    this->ui.lineDDrawCustomFps->setText("");
    if(fps == -1)
    {
        this->ui.comboDDrawFps->setCurrentIndex(0);
    }
    else if(fps == 0)
    {
        this->ui.comboDDrawFps->setCurrentIndex(1);
    }
    else
    {
        this->ui.comboDDrawFps->setCurrentIndex(2);
        this->ui.lineDDrawCustomFps->setText(QVariant(fps).toString());
    }
}

std::string SettingsWindow::saveSettings()
{
    std::string error = "";

    if(this->ui.lineNickname->text() == "")
    {
        error.append("No nickname specified, this field is mandatory!\n");
    }

    if(this->ui.lineIrcNickname->text() == "" && this->ui.checkIrcEnabled->checkState() == Qt::Checked)
    {
        error.append("No IRC nickname specified, this field is mandatory when IRC is enabled!\n");
    }

    if(this->ui.lineServer->text() == "")
    {
        this->ui.lineServer->setText("lobby.cncnet.cnc-comm.com");
        error.append("No server specified, inserted the default.\n");
    }    

    if(this->ui.lineServerPort->text() == "")
    {
        this->ui.lineServerPort->setText("8054");
        error.append("No server port specified, inserted the default.\n");
    }    
    
    if(this->ui.lineClientPort->text() == "")
    {
        this->ui.lineClientPort->setText("8054");
        error.append("No client port specified, inserted the default.\n");
    }

    if(error != "")
    {
        return error;
    }

    QSettings settings;
    settings.setValue("General/GameHandle", this->ui.lineNickname->text());
    settings.setValue("Network/Server", this->ui.lineServer->text());
    settings.setValue("Network/ServerPort", this->ui.lineServerPort->text());
    settings.setValue("Network/ClientPort", this->ui.lineClientPort->text());

    settings.setValue("CustomPath/TD", this->ui.lineTD->text());
    settings.setValue("CustomPath/RA", this->ui.lineRA->text());
    settings.setValue("CustomPath/TS", this->ui.lineTS->text());
    settings.setValue("CustomPath/RA2", this->ui.lineRA2->text());
    settings.setValue("CustomPath/RA2YR", this->ui.lineRA2YR->text());

    settings.setValue("General/UpdateOnStartup", (this->ui.checkUpdateStartup->checkState() == Qt::Checked ? true : false));
    settings.setValue("General/ConfirmGameLaunch", (this->ui.checkConfirmGameLaunch->checkState() == Qt::Checked ? true : false));
    settings.setValue("General/MinimizeToTray", (this->ui.checkMinimizeTray->checkState() == Qt::Checked ? true : false));
    settings.setValue("Network/ClientPortForce", (this->ui.checkPortForce->checkState() == Qt::Checked ? true : false));
    settings.setValue("IRC/Enabled", (this->ui.checkIrcEnabled->checkState() == Qt::Checked ? true : false));
    settings.setValue("IRC/Timestamp", (this->ui.checkIrcTimestamp->checkState() == Qt::Checked ? true : false));

    settings.setValue("General/AdvancedSettings", (this->ui.checkAdvancedSettings->checkState() == Qt::Checked ? true : false));

    settings.setValue("IRC/Nickname", this->ui.lineIrcNickname->text());

    settings.setValue("CNC-DDraw/Enabled", (this->ui.checkDDrawEnabled->checkState() == Qt::Checked ? true : false));
    settings.setValue("CNC-DDraw/Windowed", (this->ui.checkDDrawWindowed->checkState() == Qt::Checked ? true : false));
    settings.setValue("CNC-DDraw/AdjustMouse", (this->ui.checkDDrawAdjustMouse->checkState() == Qt::Checked ? true : false));
    settings.setValue("CNC-DDraw/Width", this->ui.lineDDrawWidth->text().toInt());
    settings.setValue("CNC-DDraw/Height", this->ui.lineDDrawHeight->text().toInt());

    settings.setValue("CNC-DDraw/Filter", this->ui.comboDDrawFilter->itemData(this->ui.comboDDrawFilter->currentIndex()).toString());
    settings.setValue("CNC-DDraw/Color", this->ui.comboDDrawColor->itemData(this->ui.comboDDrawColor->currentIndex()).toString());

    int fps = this->ui.comboDDrawFps->itemData(this->ui.comboDDrawFps->currentIndex()).toInt();
    if(fps == 1)
    {
        fps = this->ui.lineDDrawCustomFps->text().toInt();
    }
    settings.setValue("CNC-DDraw/Fps", fps);

    settings.setValue("General/FirstStart", false);
    settings.setValue("General/Version", _SETTINGS_VERSION);

    
    // save advanced custom paths

    for(int game=0; game<5; game++)
    {
        AdvancedGameInfo::saveGameInfos(game, this->customAdvPaths[game]);
    }

    settings.sync();

    return "";
}

void SettingsWindow::applySettings()
{
    std::string result = this->saveSettings();

    if(result != "")
    {
        QMessageBox msgBox;
        msgBox.setWindowTitle("CnCnet settings");
        msgBox.setText("Please correct the following values:");
        msgBox.setInformativeText(result.c_str());
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.setDefaultButton(QMessageBox::Ok);
        msgBox.setIcon(QMessageBox::Critical);
        msgBox.exec();
        return;
    }
    this->closed = true;
    this->close();
}

void SettingsWindow::addCustomPath()
{
    int game = this->ui.tabCustomAdvanced->currentIndex();

    AdvancedGameInfo tmp = this->addPathWindow->show(AdvancedGameInfo(Games::NOGAME));

    if(tmp.getExe() != "")
    {
        // FIXME: Why are we copying everything?
        AdvancedGameInfo newGame((Games::GameType)game, tmp.getExe(), tmp.getArgs(), tmp.getDescription());
        this->customAdvPaths[game].push_back(newGame);
    }

    this->rebuildPathTree();
}

void SettingsWindow::editCustomPath()
{
    QModelIndexList list = this->ui.treeCustomPaths->selectionModel()->selectedIndexes();

    int row = -1;
    foreach(QModelIndex index, list)
    {
        row = index.row();
        break;
    }

    int game = this->ui.tabCustomAdvanced->currentIndex();

    if(row == -1)
    {
        return;
    }

    if(this->customAdvPaths[game][row].isReadOnly())
    {
        QMessageBox msgBox;
        msgBox.setText("This game is marked read-only, it can not be edited. If this is an imported game from the simple dialog, you can edit this entry there.");
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.setDefaultButton(QMessageBox::Ok);
        msgBox.setIcon(QMessageBox::Information);
        int ret = msgBox.exec();
    }
    else
    {
        this->customAdvPaths[game][row] = this->addPathWindow->show(this->customAdvPaths[game][row]);
        
        this->rebuildPathTree();
    }
}


void SettingsWindow::delCustomPath()
{
    QModelIndexList list = this->ui.treeCustomPaths->selectionModel()->selectedIndexes();

    int row = -1;
    foreach(QModelIndex index, list)
    {
        row = index.row();
        break;
    }

    int game = this->ui.tabCustomAdvanced->currentIndex();

    if(row == -1)
    {
        return;
    }

    if(this->customAdvPaths[game][row].isReadOnly())
    {
        QMessageBox msgBox;
        msgBox.setText("This game is marked read-only, it can not be deleted. If this is an imported game from the simple dialog, you can edit this entry there.");
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.setDefaultButton(QMessageBox::Ok);
        msgBox.setIcon(QMessageBox::Information);
        int ret = msgBox.exec();
    }
    else
    {
        QMessageBox msgBox;
        msgBox.setText("Do you want to delete the selected game?");
        msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
        msgBox.setDefaultButton(QMessageBox::No);
        msgBox.setIcon(QMessageBox::Question);
        int ret = msgBox.exec();

        if(ret == QMessageBox::Yes)
        {
            this->customAdvPaths[game].erase(this->customAdvPaths[game].begin() + (row));
        }

        this->rebuildPathTree();
    }
}
